﻿import * as q from 'q';
import * as fs from 'fs';
import { TypeScriptVersionProvider, TypeScriptVersion } from '../versionProvider';
import { TypeScriptVersionPicker } from '../versionPicker';
import { TypeScriptServiceConfiguration } from '../configuration';
import API from '../api';
import * as electron from '../electron';
import * as cp from 'child_process';
import { Reader } from '../wireProtocol';
import { AppContext } from '../appContext';

export class TypeScript {
    private versionProvider: TypeScriptVersionProvider;
    private versionPicker: TypeScriptVersionPicker;
    private _configuration: TypeScriptServiceConfiguration;
    private _apiVersion: API;
    private lastError: any;
    private _tsserverVersion: any;
    private childProcess: cp.ChildProcess;
    socket: any;
    private async getTsServerArgs(
        currentVersion: TypeScriptVersion
    ): Promise<string[]> {
        const args: string[] = [];

        if (this._apiVersion.has206Features()) {
            if (this._apiVersion.has250Features()) {
                args.push('--useInferredProjectPerProjectRoot');
            } else {
                args.push('--useSingleInferredProject');
            }

            //if (this._configuration.disableAutomaticTypeAcquisition) {
            //    args.push('--disableAutomaticTypingAcquisition');
            //}
        }

        if (this._apiVersion.has208Features()) {
            args.push('--enableTelemetry');
        }

        //if (this._apiVersion.has234Features()) {
        //    if (this._configuration.npmLocation) {
        //        args.push('--npmLocation', `"${this._configuration.npmLocation}"`);
        //    }
        //}

        if (this._apiVersion.has260Features()) {
            args.push('--locale', "zh-cn");
        }
        return args;
    }


    private getDebugPort(): number | undefined {
        const value = process.env['TSS_DEBUG'];
        if (value) {
            const port = parseInt(value);
            if (!isNaN(port)) {
                return port;
            }
        }
        return undefined;
    }

    private resetClientVersion() {
        this._apiVersion = API.defaultVersion;
        this._tsserverVersion = undefined;
    }

    write(data) {
        this.childProcess.stdin.write(data, "utf8");
    }
    kill() {
        if (!this.childProcess || this.childProcess.killed) {
            return;
        }
        this.childProcess.kill();
        this.childProcess = null;
    }
    startServer() {
        this._configuration = this._configuration || TypeScriptServiceConfiguration.loadFromWorkspace(AppContext.typescriptSdkPath);
        this.versionProvider = this.versionProvider || new TypeScriptVersionProvider(this._configuration);
        this.versionPicker = new TypeScriptVersionPicker(this.versionProvider);
        return new q.promise<any>(async (resolve, reject) => {
            try {
                let currentVersion = this.versionPicker.currentVersion;

                if (!fs.existsSync(currentVersion.tsServerPath)) {
                    reject("typescript 语言服务启动失败");
                    return;
                    //this.versionPicker.useBundledVersion();
                    //currentVersion = this.versionPicker.currentVersion;
                }

                this._apiVersion = this.versionPicker.currentVersion.version || API.defaultVersion;
                const tsServerForkArgs = await this.getTsServerArgs(currentVersion);
                const debugPort = this.getDebugPort();
                const tsServerForkOptions: electron.IForkOptions = {
                    execArgv: debugPort ? [`--inspect=${debugPort}`] : [] // [`--debug-brk=5859`]
                };
                electron.fork(currentVersion.tsServerPath, tsServerForkArgs, tsServerForkOptions, (err: any, childProcess: cp.ChildProcess | null) => {
                    if (err || !childProcess) {
                        this.lastError = err;
                        this.resetClientVersion();
                        reject("typescript 语言服务启动失败");
                        return;
                    }
                    this.childProcess = childProcess;
                    childProcess.on('error', (error) => {
                        this.socket.emit("typescript", {
                            success: false,
                            event: "typescriptServerError",
                            result: error
                        });
                    });
                    childProcess.on('exit', () => {
                        this.socket.emit("typescript", {
                            success: true,
                            event: "typescriptServerExit"
                        });
                    });
                    new Reader<any>(this.childProcess.stdout, (data) => {
                        this.socket.emit("typescript", {
                            success: true,
                            event: "typescriptServerData",
                            result: {
                                success: true,
                                content: data
                            }
                        });
                    }, (err) => {
                        this.socket.emit("typescript", {
                            success: true,
                            event: "typescriptServerData",
                            result: {
                                success: false,
                                content: err
                            }
                        });
                    });
                    resolve();
                    //const handle = new ForkedTsServerProcess(childProcess);
                    //this.lastStart = Date.now();

                    //handle.onError((err: Error) => {
                    //    this.lastError = err;
                    //    this.error('TSServer errored with error.', err);
                    //    if (this.tsServerLogFile) {
                    //        this.error(`TSServer log file: ${this.tsServerLogFile}`);
                    //    }
                    //    /* __GDPR__
                    //        "tsserver.error" : {}
                    //    */
                    //    this.logTelemetry('tsserver.error');
                    //    this.serviceExited(false);
                    //});
                    //handle.onExit((code: any) => {
                    //    if (code === null || typeof code === 'undefined') {
                    //        this.info('TSServer exited');
                    //    } else {
                    //        this.error(`TSServer exited with code: ${code}`);
                    //        /* __GDPR__
                    //            "tsserver.exitWithCode" : {
                    //                "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
                    //            }
                    //        */
                    //        this.logTelemetry('tsserver.exitWithCode', { code: code });
                    //    }

                    //    if (this.tsServerLogFile) {
                    //        this.info(`TSServer log file: ${this.tsServerLogFile}`);
                    //    }
                    //    this.serviceExited(!this.isRestarting);
                    //    this.isRestarting = false;
                    //});

                    //handle.createReader(
                    //    msg => { this.dispatchMessage(msg); },
                    //    error => { this.error('ReaderError', error); });

                    //this._onReady!.resolve();
                    //resolve(handle);
                    //this._onTsServerStarted.fire();

                    //this.serviceStarted(resendModels);
                });
            } catch (error) {
                reject(error);
            }
        });
    }
}